package com.mokairui.basic.demo2;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author Mokairui
 * @Description Channel
 * @Since 2021/6/29
 */
@Slf4j(topic = "c.ChannelTest")
public class ChannelTest {

    @Test
    @SneakyThrows
    public void transferFromAndTransferTo() {
        // 1.字节输入管道
        FileInputStream fis = new FileInputStream("data.txt");
        FileChannel fisChannel = fis.getChannel();
        // 2.字节输出管道
        FileOutputStream fos = new FileOutputStream("data.txt");
        FileChannel fosChannel = fos.getChannel();

        // 3.复制数据
        fosChannel.transferFrom(fisChannel, fisChannel.position(), fisChannel.size());

        fisChannel.transferTo(fosChannel.position(), fisChannel.size(), fosChannel);

        fisChannel.close();
        fosChannel.close();
    }

    /**
     * 缓冲区的分散读和合并写
     */
    @Test
    @SneakyThrows
    public void dispersionAndMergingOfBuffer() {
        // 1.字节输入管道
        FileInputStream fis = new FileInputStream("data.txt");
        FileChannel fisChannel = fis.getChannel();
        // 2.字节输出管道
        FileOutputStream fos = new FileOutputStream("data.txt");
        FileChannel fosChannel = fos.getChannel();
        // 3.定义多个缓冲区做数据分散
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        ByteBuffer buffer1 = ByteBuffer.allocate(1024 * 1024);
        ByteBuffer[] byteBuffers = {buffer, buffer1};
        // 4.从通道中读取数据分散到各个缓冲区
        fisChannel.read(byteBuffers);
        // 5.从每个缓冲区中查询
        for (ByteBuffer byteBuffer : byteBuffers) {
            byteBuffer.flip();
            System.out.println(new String(byteBuffer.array(), 0, byteBuffer.remaining()));
        }
        // 6.聚集写入到通道
        fosChannel.write(byteBuffers);

        fisChannel.close();
        fosChannel.close();
    }

    @SneakyThrows
    @Test
    public void copy() {
        // 源文件
        File file = new File("src/main/java/com/mokairui/basic/demo2/data01.txt");
        File destFile = new File("src/main/java/com/mokairui/basic/");
        // 得到一个字节输入流
        FileInputStream fis = new FileInputStream(file);
        // 得到一个字节输出流
        FileOutputStream fos = new FileOutputStream(destFile);
        // 得到文件通道
        FileChannel fisChannel = fis.getChannel();
        FileChannel fosChannel = fos.getChannel();
        // 分配缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while (true) {
            // 必须先清空缓冲区然后在写入数据到缓冲区
            buffer.clear();
            // 开始读取数据
            int size = fisChannel.read(buffer);
            if (size == -1) {
                break;
            }
            // 已经读取了数据，把缓冲区的模式切换为可读模式
            buffer.flip();
            // 把数据写出
            fosChannel.write(buffer);
        }
        fisChannel.close();
        fosChannel.close();
    }

    @Test
    public void read() {
        try {
            // 1.定义一个文件字节输入流和源文件接通
            FileInputStream fis =
                    new FileInputStream("src/main/java/com/mokairui/basic/demo2/data01.txt");
            // 2.需要得到文件字节输入流的文件通道
            FileChannel channel = fis.getChannel();
            // 3.定义一个缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            // 4.读取数据到缓冲区
            channel.read(buffer);
            buffer.flip();
            // 5.读取出缓冲区中的数据并输出即可
            String msg = new String(buffer.array(), 0, buffer.remaining());
            System.out.println(msg);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void write() {
        try {
            // 1.字节输出流通向目标文件
            FileOutputStream fos =
                    new FileOutputStream("src/main/java/com/mokairui/basic/demo2/data01.txt");
            // 2.得到字节输出流对应的通道Channel
            FileChannel channel = fos.getChannel();
            // 3.分配缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.put("hello, nio".getBytes());
            // 4.把缓冲区切换为写模式
            buffer.flip();
            channel.write(buffer);
            buffer.clear();
            channel.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
